﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Cofe.Core.Filter;
using Cofe.Web;

namespace Cofe.Core
{
    /// <summary>
    /// Used by Web Services, user can access :
    /// all major metadata in the property irself or a list. (e.g. \api\entry\{id} or \api\entry\{id}\list)
    /// all minor and major metadata in metadata resource (e.g. \api\entry\{id}\metadata)
    /// 
    /// </summary>
    public class WebMetadataAttribute : WebAccessAttribute
    {        
        /// <summary>
        /// Whether it is a major property? if yes, it will embed it when returning COFE.Web.Entry to web services.
        /// </summary>
        protected bool _majorProperty;

        public override bool IsMajorProperty<T>()
        {
            return _majorProperty;
        }

        public WebMetadataAttribute(bool majorProperty)
            : base(MediaType.Stream, majorProperty ? WebAccessType.Property : WebAccessType.Metadata, RelationType.Property)
        {
            _majorProperty = majorProperty;
        }


        public WebMetadataAttribute()
            : this(false)
        {

        }

    }

    

    /// <summary>
    /// Used by Web Services, user can access the property as resource (e.g. \contents\{id}\resourceName)
    /// all major resource is advertised in the entry (e.g. \api\entry\{id}) as links
    /// all minor and major resource is advertised in resource call (e.g. \api\entry\{id}\resource) as links
    /// </summary>
    public class WebResourceAttribute : WebAccessAttribute
    {
        /// <summary>
        /// The resource is available as the specified type when in web services, conversion may be required.
        /// </summary>
        public MediaType MediaType { get; private set; }
        public WebCacheMethod CacheMethod { get; private set; }
        public virtual string[] Parameters { get; private set; }

        protected bool _majorProperty;

        public override bool IsMajorProperty<T>()
        {
            return _majorProperty;
        }

        public WebResourceAttribute(MediaType mediaType, RelationType relationType, bool majorResource,
            WebCacheMethod cacheMethod, params string[] parameters)
            : base(mediaType, WebAccessType.Resource, relationType)
        {
            CacheMethod = cacheMethod;
            Parameters = parameters;
            MediaType = mediaType;
            _majorProperty = majorResource;
        }

        public WebResourceAttribute(MediaType mediaType, bool majorResource,
            WebCacheMethod cacheMethod, params string[] parameters)
            : base(mediaType, WebAccessType.Resource, RelationType.Property)
        {
            CacheMethod = cacheMethod;
            Parameters = parameters;
            MediaType = mediaType;
            _majorProperty = majorResource;
        }
    }

    public class WebListResourceAttribute : WebResourceAttribute
    {
        private static string[] getParameters()
        {
            var eofp = CofeServices.ServiceLocater.FindService<IEntryOptionFilterParser>();
            return eofp.FilterConstructor.FilterFactories.SelectMany(f => f.SupportedFilterTypes.Keys)
                .Distinct()
                .ToArray();            
        }

        private string[] _parameters = null;

        public override string[] Parameters { get { return _parameters ?? (_parameters = getParameters()); } }

        public WebListResourceAttribute(MediaType mediaType, RelationType relationType, bool majorResource = true)
            : base(mediaType, relationType, majorResource, WebCacheMethod.LastModified)
        {

        }
    }

    public enum PropertyXmlType { Attribute, Element };
    public class WebPropertyAttribute : WebMetadataAttribute
    {
        private Type[] _whenType;
        private bool _asAttribute;

        public WebPropertyAttribute(PropertyXmlType type, params Type[] isMajorWhenType)
            : base(true)
        {
            _whenType = isMajorWhenType;
            _asAttribute = type == PropertyXmlType.Attribute;
        }

        public override bool SerializeAsAttribute { get { return _asAttribute; } }

        public override bool IsMajorProperty<T>()
        {
            if (_whenType.Length == 0)
                return true;
            else
                foreach (var type in _whenType)
                    if (typeof(T).Equals(type))
                        return true;
            return false;
        }
    }

    public class WebActionAttribute : WebResourceAttribute
    {
        private Type[] _whenType;
        public WebActionAttribute(MediaType mediaType, WebAccessType accessType, RelationType relationType, bool isMajorProperty, params Type[] isMajorWhenType)
            : base(mediaType, isMajorProperty, WebCacheMethod.None)
        {
            _whenType = isMajorWhenType;
            WebAccessType = accessType;
            RelationType = relationType;
        }

        public WebActionAttribute(WebAccessType accessType, RelationType relationType, bool isMajorProperty, params Type[] isMajorWhenType)
            : this(MediaType.None, accessType, relationType, isMajorProperty, isMajorWhenType)
        {
        }

        public override bool IsMajorProperty<T>()
        {
            if (!(base.IsMajorProperty<T>()))
                return false;

            if (_whenType.Length == 0)
                return true;
            else
                foreach (var type in _whenType)
                    if (typeof(T).Equals(type))
                        return true;
            return false;
        }
    }
    
}
